﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Linq;
using PengSW.XmlTools;
using System.Data;
using System.Data.Common;

namespace PengSW.XmlDb
{
    public class XmlToFieldRule
    {
        public string FieldName { get; set; }
        public string XPath { get; set; }
        public string DataType { get; set; }
        public string Format { get; set; }
        public bool NotNull { get; set; }
        public string DefaultValue { get; set; }

        public bool NeedQuot 
        { 
            get 
            {
                switch (DataType.Trim().ToUpper())
                {
                    case "INT" :
                    case "DOUBLE" :
                        return false;
                }
                return true;
            } 
        }
        public bool IsValid { get { return FieldName.Trim() != string.Empty && DataType.Trim() != string.Empty; } }

        public void ReadFromXml(XElement aXElement)
        {
            try
            {
                FieldName = aXElement.GetAttributeValue("Name", "");
                XPath = aXElement.GetAttributeValue("XPath", "");
                DataType = aXElement.GetAttributeValue("DataType", "VARCHAR(45)");
                Format = aXElement.GetAttributeValue("Format", "");
                DefaultValue = aXElement.GetAttributeValue("DefaultValue", "");
                NotNull = Convert.ToBoolean(aXElement.GetAttributeValue("NotNull", "False"));
            }
            catch
            {
            }
        }

        public XElement CreateXElement()
        {
            return new XElement("Field",
                new XAttribute("Name", FieldName),
                new XAttribute("XPath", XPath),
                new XAttribute("DataType", DataType),
                new XAttribute("Format", Format),
                new XAttribute("NotNull", NotNull),
                new XAttribute("DefaultValue", DefaultValue));
        }
    }

    public class XmlToFieldRules : System.Collections.Generic.List<XmlToFieldRule>
    {
        public void ReadFromXml(XElement aXElement)
        {
            Clear();
            foreach (XElement aFieldXElement in aXElement.Elements("Field"))
            {
                XmlToFieldRule aField = new XmlToFieldRule();
                aField.ReadFromXml(aFieldXElement);
                if (aField.IsValid) Add(aField);
            }
        }
    }

    public class XmlToTableRule
    {
        public XmlToTableRule()
        {
            FieldRules = new XmlToFieldRules();
            SubTableRules = new XmlToTableRules();
        }

        public string TableName { get; set; }
        public string XPath { get; set; }
        public string IdFieldName { get; set; }
        public string ParentIdFieldName { get; set; }

        public bool IsValid { get { return TableName.Trim() != string.Empty; } }

        public XmlToFieldRules FieldRules { get; private set; }
        public XmlToTableRules SubTableRules { get; private set; }

        public void ReadFromXml(XElement aXElement)
        {
            try
            {
                TableName = aXElement.GetAttributeValue("Name", "");
                XPath = aXElement.GetAttributeValue("XPath", "");
                IdFieldName = aXElement.GetAttributeValue("Id", "");
                ParentIdFieldName = aXElement.GetAttributeValue("ParentId", "");

                FieldRules.ReadFromXml(aXElement);
                SubTableRules.ReadFromXml(aXElement);
            }
            catch
            {
            }
        }

        public XElement CreateXElement()
        {
            return new XElement("Table",
                new XAttribute("Name", TableName),
                new XAttribute("XPath", XPath),
                new XAttribute("Id", IdFieldName),
                new XAttribute("ParentId", ParentIdFieldName),
                from aField in FieldRules select aField.CreateXElement(),
                from aTable in SubTableRules select aTable.CreateXElement());
        }

        public DataTable CreateDataTableInto(DataSet aDataSet)
        {
            DataTable aDataTable = new DataTable(TableName);
            foreach (XmlToFieldRule aFieldRule in FieldRules)
            {
                aDataTable.Columns.Add(aFieldRule.FieldName);
            }
            aDataSet.Tables.Add(aDataTable);

            // 创建子表
            foreach (XmlToTableRule aSubTableRule in SubTableRules)
            {
                DataTable aSubDataTable = aSubTableRule.CreateDataTableInto(aDataSet);
                DataRelation aDataRelation = new DataRelation("", aDataTable.Columns[IdFieldName], aSubDataTable.Columns[aSubTableRule.ParentIdFieldName]);
                aDataSet.Relations.Add(aDataRelation);
            }

            return aDataTable;
        }
    }

    public class XmlToTableRules : System.Collections.Generic.List<XmlToTableRule>
    {
        public void ReadFromXml(XElement aXElement)
        {
            Clear();
            foreach (XElement aTableXElement in aXElement.Elements("Table"))
            {
                XmlToTableRule aTable = new XmlToTableRule();
                aTable.ReadFromXml(aTableXElement);
                if (aTable.IsValid) Add(aTable);
            }
        }

        public void LoadFromXmlFile(string aFileName)
        {
            XDocument aXDocument = XDocument.Load(aFileName);
            ReadFromXml(aXDocument.Root);
        }

        public void LoadFromXml(string aXml)
        {
            System.IO.StringReader aStream = new System.IO.StringReader(aXml);
            XDocument aXDocument = XDocument.Load(aStream);
            ReadFromXml(aXDocument.Root);
        }

        public void CreateDataTablesInto(DataSet aDataSet)
        {
            foreach (XmlToTableRule aTableRule in this)
            {
                aTableRule.CreateDataTableInto(aDataSet);
            }
        }
    }

    public interface XmlDbRule
    {
        string GetCreateTableSql(XmlToTableRule aTableRule);
        string GetInsertSql(XmlToTableRule aTableRule, XElement aRecordXElement, out string aId, string aParentId);
        string GetDropTableSql(XmlToTableRule aTableRule);
    }
}
